package com.zh.job.cycle;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.zh.constant.ProjectConstant;
import com.zh.domain.entity.*;
import com.zh.manager.ThreadManager;
import com.zh.mapper.MilestoneMapper;
import com.zh.mapper.ProjectMapper;
import com.zh.service.*;
import kotlin.jvm.internal.Lambda;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Component
@Slf4j
public class OverdueTask {

    @Resource
    private ProjectMapper projectMapper;

    @Resource
    private ProjectService projectService;
    @Resource
    private MilestoneService milestoneService;
    @Resource
    private MilestoneMapper milestoneMapper;
    @Resource
    private IterationService iterationService;
    @Resource
    private RequirementsService requirementsService;
    @Resource
    private TaskService taskService;
    @Resource
    private ProjectUserService projectUserService;
    @Resource
    private MessageService messageService;

    // Caffeine 缓存，存储已经发送过过期消息的对象 ID
    private Cache<String, LocalDateTime> overdueCache;

    @PostConstruct
    public void init() {
        overdueCache = Caffeine.newBuilder()
                .expireAfterWrite(Duration.ofHours(1)) // 缓存1小时
                .build();
    }
    /**
     * 1分钟检查一次项目是否逾期
     */
    @Scheduled(fixedRate = 60 * 1000, initialDelay = 0)
    public void checkProjectExpiration() {
        log.info("开始检查项目是否过期...");

        // 查询所有过期的项目
        LambdaQueryWrapper<Project> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.lt(Project::getEndTime, LocalDateTime.now())
                .lt(Project::getProgress, BigDecimal.valueOf(1))
                .ne(Project::getStatus, ProjectConstant.PROJECT_STATUS_OVERDUE)
                .ne(Project::getStatus, ProjectConstant.PROJECT_STATUS_COMPLETED);
        List<Project> expiredProjects = projectMapper.selectList(queryWrapper);
        if (CollectionUtil.isEmpty(expiredProjects)) {
            log.info("没有项目过期");
            return;
        }
        for (Project project : expiredProjects) {
            String cacheKey = "project:" + project.getId();
            if (overdueCache.getIfPresent(cacheKey) != null) {
                log.info("项目 {} 已经发送过过期消息，跳过", project.getId());
                continue;
            }
            ThreadManager.execute(() -> {
                try {
                    updateProjectStatus(project);
                    sendOverdueMessage(project);
                    overdueCache.put(cacheKey, LocalDateTime.now());
                } catch (Exception e) {
                    log.error("项目 {} 过期执行失败", project.getId(), e);
                }
            });
        }
    }


    private void updateProjectStatus(Project project) {
        log.info("项目 {} 过期，更新状态为过期", project.getId());
        Project updateProject = new Project();
        updateProject.setId(project.getId());
        updateProject.setUpdateAt(LocalDateTime.now());
        updateProject.setStatus(ProjectConstant.PROJECT_STATUS_OVERDUE);
        boolean success = projectService.updateById(updateProject);
        if (success) {
            log.info("项目 {} 已过期，状态更新成功", project.getId());
        } else {
            log.error("项目 {} 状态更新失败", project.getId());
        }
    }

    private void sendOverdueMessage(Project project) {
        log.info("发送项目 {} 过期消息给项目成员", project.getId());
        LambdaQueryWrapper<ProjectUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ProjectUser::getProId, project.getId());
        List<Integer> userIdList = projectUserService.list(queryWrapper)
                .stream()
                .map(ProjectUser::getUserId)
                .collect(Collectors.toList());
        Message message = new Message();
        message.setSendId(project.getOwnerId());
        message.setContent(String.format("项目 %s 已逾期 请尽快处理", project.getTitle()));
        message.setCreateAt(LocalDateTime.now());
        message.setCreateBy(project.getOwnerId());
        message.setUpdateAt(LocalDateTime.now());
        message.setUpdateBy(project.getOwnerId());
        message.setNoticeType(0);
        message.setType(1);
        message.setParams(Map.of(
                "proId", project.getId().toString(),
                "payloadType", "project",
                "title", project.getTitle(),
                "type", 1
        ));
        message.setStatus(1);
        message.setDeleted(0);
        messageService.sendMessage(message, userIdList);
    }


    /**
     * 1分钟检查一次里程碑是否逾期
     */
    @Scheduled(fixedRate = 60 * 1000, initialDelay = 1000)
    public void checkMilestoneExpiration() {
        log.info("开始检查里程碑是否过期...");

        // 查询所有过期的里程碑
        LambdaQueryWrapper<Milestone> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Milestone::getDeleted, 0)
                .ne(Milestone::getStatus, ProjectConstant.PROJECT_STATUS_OVERDUE)
                .ne(Milestone::getStatus, ProjectConstant.PROJECT_STATUS_COMPLETED)
                .lt(Milestone::getEndTime, LocalDateTime.now());
        List<Milestone> expiredMilestones = milestoneMapper.selectList(queryWrapper);
        if (CollectionUtil.isEmpty(expiredMilestones)) {
            log.info("没有里程碑过期");
            return;
        }
        for (Milestone milestone : expiredMilestones) {
            String cacheKey = "milestone:" + milestone.getId();
            if (overdueCache.getIfPresent(cacheKey) != null) {
                log.info("里程碑 {} 已经发送过过期消息，跳过", milestone.getId());
                continue;
            }
            ThreadManager.execute(() -> {
                try {
                    updateMilestoneStatus(milestone);
                    sendOverdueMessage(milestone);
                    overdueCache.put(cacheKey, LocalDateTime.now());
                } catch (Exception e) {
                    log.error("里程碑 {} 过期执行失败", milestone.getId(), e);
                }
            });
        }
    }

    private void updateMilestoneStatus(Milestone milestone) {
        log.info("里程碑 {} 过期，更新状态为过期", milestone.getId());
        Milestone updateMilestone = new Milestone();
        updateMilestone.setId(milestone.getId());
        updateMilestone.setUpdateAt(LocalDateTime.now());
        updateMilestone.setStatus(ProjectConstant.PROJECT_STATUS_OVERDUE);
        boolean success = milestoneService.updateById(updateMilestone);
        if (success) {
            log.info("里程碑 {} 已过期，状态更新成功", milestone.getId());
        } else {
            log.error("里程碑 {} 状态更新失败", milestone.getId());
        }
    }

    private void sendOverdueMessage(Milestone milestone) {
        log.info("发送里程碑 {} 过期消息给里程碑成员", milestone.getId());
        Integer proId = milestone.getProId();
        Project project = projectService.getById(proId);
        LambdaQueryWrapper<ProjectUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ProjectUser::getProId, project.getId());
        List<Integer> userIdList = projectUserService.list(queryWrapper)
                .stream()
                .map(ProjectUser::getUserId)
                .collect(Collectors.toList());
        Message message = new Message();
        message.setSendId(project.getOwnerId());
        message.setContent(String.format("项目 %s 里程碑 %s 已逾期 请尽快处理", project.getTitle(), milestone.getTitle()));
        message.setCreateAt(LocalDateTime.now());
        message.setCreateBy(project.getOwnerId());
        message.setUpdateAt(LocalDateTime.now());
        message.setUpdateBy(project.getOwnerId());
        message.setNoticeType(0);
        message.setType(1);
        message.setParams(Map.of(
                "proId", project.getId().toString(),
                "payloadType", "project",
                "title", project.getTitle(),
                "type", 1
        ));
        message.setStatus(1);
        message.setDeleted(0);
        messageService.sendMessage(message, userIdList);
    }

    /**
     * 1分钟检查一次迭代是否逾期
     */
    @Scheduled(fixedRate = 60 * 1000, initialDelay = 2000)
    public void checkIterationExpiration() {
        log.info("开始检查迭代是否过期...");

        // 查询所有过期的里程碑
        LambdaQueryWrapper<Iteration> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Iteration::getDeleted, 0)
                .ne(Iteration::getStatus, ProjectConstant.PROJECT_STATUS_OVERDUE)
                .ne(Iteration::getStatus, ProjectConstant.PROJECT_STATUS_COMPLETED)
                .lt(Iteration::getEndTime, LocalDateTime.now());
        List<Iteration> expiredIterations = iterationService.list(queryWrapper);
        if (CollectionUtil.isEmpty(expiredIterations)) {
            log.info("没有迭代过期");
            return;
        }
        for (Iteration iteration : expiredIterations) {
            String cacheKey = "iteration:" + iteration.getId();
            if (overdueCache.getIfPresent(cacheKey) != null) {
                log.info("迭代 {} 已经发送过过期消息，跳过", iteration.getId());
                continue;
            }
            ThreadManager.execute(() -> {
                try {
                    updateIterationStatus(iteration);
                    sendOverdueMessage(iteration);
                    overdueCache.put(cacheKey, LocalDateTime.now());
                } catch (Exception e) {
                    log.error("迭代 {} 过期执行失败", iteration.getId(), e);
                }
            });
        }
    }

    private void updateIterationStatus(Iteration iteration) {
        log.info("迭代 {} 过期，更新状态为过期", iteration.getId());
        Iteration updateIteration = new Iteration();
        updateIteration.setId(iteration.getId());
        updateIteration.setUpdateAt(LocalDateTime.now());
        updateIteration.setStatus(ProjectConstant.PROJECT_STATUS_OVERDUE);
        boolean success = iterationService.updateById(updateIteration);
        if (success) {
            log.info("迭代 {} 已过期，状态更新成功", iteration.getId());
        } else {
            log.error("迭代 {} 状态更新失败", iteration.getId());
        }
    }

    private void sendOverdueMessage(Iteration iteration) {
        log.info("发送迭代 {} 过期消息给里程碑成员", iteration.getId());
        Integer proId = iteration.getProId();
        Project project = projectService.getById(proId);
        LambdaQueryWrapper<ProjectUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ProjectUser::getProId, project.getId());
        List<Integer> userIdList = projectUserService.list(queryWrapper)
                .stream()
                .map(ProjectUser::getUserId)
                .collect(Collectors.toList());
        Message message = new Message();
        message.setSendId(project.getOwnerId());
        message.setContent(String.format("项目 %s 迭代 %s 已逾期 请尽快处理", project.getTitle(), iteration.getTitle()));
        message.setCreateAt(LocalDateTime.now());
        message.setCreateBy(project.getOwnerId());
        message.setUpdateAt(LocalDateTime.now());
        message.setUpdateBy(project.getOwnerId());
        message.setNoticeType(0);
        message.setType(1);
        message.setParams(Map.of(
                "proId", project.getId().toString(),
                "payloadType", "project",
                "title", project.getTitle(),
                "type", 1
        ));
        message.setStatus(1);
        message.setDeleted(0);
        messageService.sendMessage(message, userIdList);
    }

    /**
     * 1分钟检查一次需求是否逾期
     */
    @Scheduled(fixedRate = 60 * 1000, initialDelay = 3000)
    public void checkRequirementExpiration() {
        log.info("开始检查需求是否过期...");

        // 查询所有过期的里程碑
        LambdaQueryWrapper<Requirements> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Requirements::getDeleted, 0)
                .ne(Requirements::getStatus, ProjectConstant.PROJECT_STATUS_OVERDUE)
                .ne(Requirements::getStatus, ProjectConstant.PROJECT_STATUS_COMPLETED)
                .lt(Requirements::getEndTime, LocalDateTime.now());
        List<Requirements> expiredRequirements = requirementsService.list(queryWrapper);
        if (CollectionUtil.isEmpty(expiredRequirements)) {
            log.info("没有需求过期");
            return;
        }
        for (Requirements requirements : expiredRequirements) {
            String cacheKey = "requirement:" + requirements.getId();
            if (overdueCache.getIfPresent(cacheKey) != null) {
                log.info("需求 {} 已经发送过过期消息，跳过", requirements.getId());
                continue;
            }
            ThreadManager.execute(() -> {
                try {
                    updateRequirementStatus(requirements);
                    sendOverdueMessage(requirements);
                    overdueCache.put(cacheKey, LocalDateTime.now());
                } catch (Exception e) {
                    log.error("需求 {} 过期执行失败", requirements.getId(), e);
                }
            });
        }
    }

    private void updateRequirementStatus(Requirements requirement) {
        log.info("需求 {} 过期，更新状态为过期", requirement.getId());
        Requirements updateRequirement = new Requirements();
        updateRequirement.setId(requirement.getId());
        updateRequirement.setUpdateAt(LocalDateTime.now());
        updateRequirement.setStatus(ProjectConstant.PROJECT_STATUS_OVERDUE);
        boolean success = requirementsService.updateById(updateRequirement);
        if (success) {
            log.info("需求 {} 已过期，状态更新成功", requirement.getId());
        } else {
            log.error("需求 {} 状态更新失败", requirement.getId());
        }
    }

    private void sendOverdueMessage(Requirements requirements) {
        log.info("发送需求 {} 过期消息给负责人", requirements.getId());
        Message message = new Message();
        message.setSendId(requirements.getOwnerId());
        message.setContent(String.format("需求 %s 已逾期 请尽快处理", requirements.getTitle()));
        message.setCreateAt(LocalDateTime.now());
        message.setCreateBy(requirements.getOwnerId());
        message.setUpdateAt(LocalDateTime.now());
        message.setUpdateBy(requirements.getOwnerId());
        message.setNoticeType(0);
        message.setType(3);
        message.setParams(Map.of(
                "reqId", requirements.getId().toString(),
                "payloadType", "requirement",
                "title", requirements.getTitle(),
                "type", 3
        ));
        message.setStatus(1);
        message.setDeleted(0);
        messageService.sendMessage(message, List.of(requirements.getOwnerId()));
    }

    /**
     * 1分钟检查一次任务是否逾期
     */
    @Scheduled(fixedRate = 60 * 1000, initialDelay = 4000)
    public void checkTaskExpiration() {
        log.info("开始检查任务是否过期...");

        // 查询所有过期的任务
        LambdaQueryWrapper<Task> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Task::getDeleted, 0)
                .ne(Task::getStatus, ProjectConstant.PROJECT_STATUS_OVERDUE)
                .ne(Task::getStatus, ProjectConstant.PROJECT_STATUS_COMPLETED)
                .lt(Task::getEndTime, LocalDateTime.now());
        List<Task> expiredTasks = taskService.list(queryWrapper);
        if (CollectionUtil.isEmpty(expiredTasks)) {
            log.info("没有任务过期");
            return;
        }
        for (Task task : expiredTasks) {
            String cacheKey = "task:" + task.getId();
            if (overdueCache.getIfPresent(cacheKey) != null) {
                log.info("任务 {} 已经发送过过期消息，跳过", task.getId());
                continue;
            }
            ThreadManager.execute(() -> {
                try {
                    updateTaskStatus(task);
                    sendOverdueMessage(task);
                    overdueCache.put(cacheKey, LocalDateTime.now());
                } catch (Exception e) {
                    log.error("任务 {} 过期执行失败", task.getId(), e);
                }
            });
        }
    }

    private void updateTaskStatus(Task task) {
        log.info("任务 {} 过期，更新状态为过期", task.getId());
        Task updateTask = new Task();
        updateTask.setId(task.getId());
        updateTask.setUpdateAt(LocalDateTime.now());
        updateTask.setStatus(ProjectConstant.PROJECT_STATUS_OVERDUE);
        boolean success = taskService.updateById(updateTask);
        if (success) {
            log.info("任务 {} 已过期，状态更新成功", task.getId());
        } else {
            log.error("任务 {} 状态更新失败", task.getId());
        }
    }

    private void sendOverdueMessage(Task task) {
        log.info("发送任务 {} 过期消息给负责人", task.getId());
        Message message = new Message();
        message.setSendId(task.getOwnerId());
        message.setContent(String.format("任务 %s 已逾期 请尽快处理", task.getTitle()));
        message.setCreateAt(LocalDateTime.now());
        message.setCreateBy(task.getOwnerId());
        message.setUpdateAt(LocalDateTime.now());
        message.setUpdateBy(task.getOwnerId());
        message.setNoticeType(0);
        message.setType(2);
        message.setParams(Map.of(
                "taskId", task.getId().toString(),
                "payloadType", "task",
                "title", task.getTitle(),
                "type", 2
        ));
        message.setStatus(1);
        message.setDeleted(0);
        messageService.sendMessage(message, List.of(task.getOwnerId()));
    }
}
